package com.eight.cloud.payment.controller;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.eight.cloud.client.model.dto.OrderDto;
import com.eight.cloud.client.model.dto.PlatformOrderDto;
import com.eight.cloud.client.model.dto.RefundDto;
import com.eight.cloud.client.model.vo.OrderVo;
import com.eight.cloud.client.model.vo.RefundVo;
import com.eight.cloud.core.global.model.BaseUser;
import com.eight.cloud.core.global.result.Result;
import com.eight.cloud.core.utils.supply.UserContext;
import com.eight.cloud.openapi.annotations.OpenApi;
import com.eight.cloud.payment.common.enums.PayChannelEnum;
import com.eight.cloud.payment.common.enums.PayStrategyEnum;
import com.eight.cloud.payment.common.enums.TradeTypeEnum;
import com.eight.cloud.payment.facade.OrderFacade;
import com.eight.cloud.payment.model.vo.SubPayOrderVo;
import com.eight.cloud.payment.model.vo.SubRefundOrderVo;
import com.eight.cloud.payment.service.IMerchantAppService;
import com.eight.cloud.payment.service.ISubPayOrderService;
import com.eight.cloud.payment.service.ISubRefundOrderService;
import com.eight.cloud.payment.service.IThirdPayService;
import com.wechat.pay.java.core.exception.MalformedMessageException;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.exception.ValidationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

/**
 * 第三方支付控制器
 *
 * @ClassName: ThirdPayController
 * @Author: TXC
 * @Date: 2024-12-26 10:11
 **/
@Slf4j
@RestController
@RequestMapping("/v1/payment/{channel}/{type}")
public class PaymentController {
    @Resource
    IThirdPayService thirdPayService;
    @Resource
    private IMerchantAppService merchantAppService;
    @Resource
    private OrderFacade orderFacade;
    @Resource
    private ISubPayOrderService subPayOrderService;
    @Resource
    private ISubRefundOrderService subRefundOrderService;


    /**
     * 预下单
     *
     * @param channel       支付渠道
     * @param type          支付类型
     * @param order  订单信息
     * @return @Link Result
     */
    @OpenApi
    @PostMapping("placeOrder")
    public Result<String> pay(@PathVariable String channel, @PathVariable String type, @RequestBody OrderDto order) {
        checkSubMerchantId(order.getSubMerchantId());
        try {
            SubPayOrderVo subPayOrder = orderFacade.addPayOrder(PayStrategyEnum.getEnum(PayChannelEnum.getByCode(channel), TradeTypeEnum.getByCode(type)), order);
            PlatformOrderDto platformOrderDto = BeanUtil.toBean(order, PlatformOrderDto.class);
            platformOrderDto.setUuid(subPayOrder.getUuid());
            platformOrderDto.setAppid(subPayOrder.getAppid());
            String result = thirdPayService.thirdPay(PayStrategyEnum.getEnum(PayChannelEnum.getByCode(channel), TradeTypeEnum.getByCode(type)), platformOrderDto);
            return Result.ok(result);
        } catch (ServiceException e) {
            return Result.fail(e.getErrorMessage());
        } catch (MalformedMessageException | ValidationException e) {
            return Result.fail(e.getMessage());
        }
    }


    /**
     * 退款
     *
     * @param channel       支付渠道
     * @param type          支付类型
     * @param refund 退款信息
     * @return 结果
     */
    @OpenApi
    @PostMapping("refund")
    public Result<String> refund(@PathVariable String channel, @PathVariable String type,
                                 @RequestBody RefundDto refund) {
        checkSubMerchantId(refund.getSubMerchantId());
        try {
            SubRefundOrderVo subRefundOrder = orderFacade.addRefundOrder(PayStrategyEnum.getEnum(PayChannelEnum.getByCode(channel), TradeTypeEnum.getByCode(type)), refund);
            String result = thirdPayService.refund(PayStrategyEnum.getEnum(PayChannelEnum.getByCode(channel), TradeTypeEnum.getByCode(type)), subRefundOrder,
                    refund.getNotifyUrl());
            return Result.ok(result);
        } catch (ServiceException e) {
            return Result.fail(e.getErrorMessage());
        } catch (MalformedMessageException | ValidationException e) {
            return Result.fail(e.getMessage());
        }
    }

    /**
     * 退款订单查询
     *
     * @param channel       支付渠道
     * @param type          支付类型
     * @param outRefundNo   退款订单号
     * @param subMerchantId 指定商户号（不可为空）
     * @return 详情
     */
    @OpenApi
    @GetMapping("queryByOutRefundNo")
    public Result<RefundVo> queryByOutRefundNo(@PathVariable String channel, @PathVariable String type,
                                               String outRefundNo, String subMerchantId) {
        checkSubMerchantId(subMerchantId);
        try {
            BaseUser user = UserContext.getUser();
            assert user != null;
            SubRefundOrderVo subRefundOrderVo = subRefundOrderService.findSubRefundOrder(subMerchantId, outRefundNo,
                    user.getUuid());
            RefundVo result = thirdPayService.queryByOutRefundNo(PayStrategyEnum.getEnum(PayChannelEnum.getByCode(channel), TradeTypeEnum.getByCode(type)),
                    subRefundOrderVo);
            return Result.ok(result);
        } catch (ServiceException e) {
            return Result.fail(e.getErrorMessage());
        } catch (MalformedMessageException | ValidationException e) {
            return Result.fail(e.getMessage());
        }
    }


    /**
     * 根据流水号查询订单
     *
     * @param channel       支付渠道
     * @param type          支付类型
     * @param transactionId 流水号
     * @param subMerchantId 指定商户号（不可为空）
     * @return 结果
     */
    @OpenApi
    @GetMapping("queryOrderById")
    public Result<OrderVo> queryOrderById(@PathVariable String channel, @PathVariable String type, String transactionId
            , String subMerchantId) {
        checkSubMerchantId(subMerchantId);
        try {
            BaseUser user = UserContext.getUser();
            assert user != null;
            SubPayOrderVo subPayOrder = subPayOrderService.findSubPayOrderByTransactionId(subMerchantId,
                    transactionId, user.getUuid());
            OrderVo result = thirdPayService.queryOrderById(PayStrategyEnum.getEnum(PayChannelEnum.getByCode(channel), TradeTypeEnum.getByCode(type)), subPayOrder);
            return Result.ok(result);
        } catch (ServiceException e) {
            return Result.fail(e.getErrorMessage());
        } catch (MalformedMessageException | ValidationException e) {
            return Result.fail(e.getMessage());
        }
    }

    /**
     * 根据商户订单号查询订单
     *
     * @param channel       支付渠道
     * @param type          支付类型
     * @param outTradeNo    商户订单id
     * @param subMerchantId 指定商户号（不可为空）
     * @return 结果
     */
    @OpenApi
    @GetMapping("queryOrderByOutTradeNo")
    public Result<OrderVo> queryOrderByOutTradeNo(@PathVariable String channel, @PathVariable String type,
                                                  String outTradeNo, String subMerchantId) {
        checkSubMerchantId(subMerchantId);
        try {
            BaseUser user = UserContext.getUser();
            assert user != null;
            SubPayOrderVo subPayOrder = subPayOrderService.findSubPayOrder(subMerchantId, outTradeNo, user.getUuid());
            OrderVo result = thirdPayService.queryOrderByOutTradeNo(PayStrategyEnum.getEnum(PayChannelEnum.getByCode(channel), TradeTypeEnum.getByCode(type)),
                    subPayOrder);
            return Result.ok(result);
        } catch (ServiceException e) {
            return Result.fail(e.getErrorMessage());
        } catch (MalformedMessageException | ValidationException e) {
            return Result.fail(e.getMessage());
        }
    }

    /**
     * 关闭订单
     *
     * @param channel       支付渠道
     * @param type          支付类型
     * @param outTradeNo    商户订单id
     * @param subMerchantId 指定商户号（不可为空）
     * @return 结果
     */
    @OpenApi
    @GetMapping("closeOrder")
    public Result<String> closeOrder(@PathVariable String channel, @PathVariable String type, String outTradeNo,
                                     String subMerchantId) {
        checkSubMerchantId(subMerchantId);
        try {
            BaseUser user = UserContext.getUser();
            assert user != null;
            SubPayOrderVo subPayOrder = subPayOrderService.findSubPayOrder(subMerchantId, outTradeNo, user.getUuid());
            String result = thirdPayService.closeOrder(PayStrategyEnum.getEnum(PayChannelEnum.getByCode(channel), TradeTypeEnum.getByCode(type)), subPayOrder);
            return Result.ok(result);
        } catch (ServiceException e) {
            return Result.fail(e.getErrorMessage());
        } catch (MalformedMessageException | ValidationException e) {
            return Result.fail(e.getMessage());
        }
    }

    private void checkSubMerchantId(String subMerchantId) {
        BaseUser user = UserContext.getUser();
        if (ObjectUtil.isNull(user)) {
            log.error("app用户为空");
            throw new RuntimeException("商户号错误");
        }
        boolean isAuthorize;
        try {
            isAuthorize = merchantAppService.isAuthorizeApp(user.getUuid(), subMerchantId);
        } catch (Exception e) {
            log.error("查询app商户号授权失败", e);
            throw new RuntimeException("商户号错误");
        }
        if (!isAuthorize) {
            throw new RuntimeException("未授予app商户号使用权");
        }
    }

}
